/* Copyright 2009 Requirements Management System 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mags.remas.model.entity.provider;

// Generated Dec 6, 2009 5:47:57 PM by Hibernate Tools 3.2.2.GA
// powered by MAGS

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.map.MultiValueMap;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.mags.dao.common.ERestrictionOperator;
import org.mags.dao.common.ESortOrder;
import org.mags.dao.common.IRestrictionBuilder;
import org.mags.dao.provider.NoCacheableDataProvider;
import org.mags.remas.model.entity.CommentType;
import org.mags.remas.model.entity.Entity;
import org.mags.remas.model.entity.EntityComment;
import org.mags.remas.model.entity.EntityRelationship;
import org.mags.remas.model.entity.EntityType;
import org.mags.remas.model.entity.KeyValue;

public class EntityRelationshipProvider extends NoCacheableDataProvider<EntityRelationship> {
	private static final long serialVersionUID = 1L;
	private EntityTypeProvider entityTypeProvider;	
	private KeyTypeProvider keyTypeProvider;
	
	public long countWithCommentsBySample(EntityRelationship filter) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		makeFilter(filter, restrictionBuilder);
		return super.getSize(new String[]{"entity as entity", "entityParent as entityParent", "entity.entityComments as entityComment innerJoin"}, restrictionBuilder);
	}	
	@SuppressWarnings("rawtypes")
	public MultiValueMap findWithCommentsBySample(EntityRelationship filter, int firstRecord, int numRecords) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		makeFilter(filter, restrictionBuilder);
		List list = super.getByRestrictionAsMaps(new String[]{"entity as entity", "entityParent as entityParent", "entity.entityComments as entityComment innerJoin"}, restrictionBuilder, new String[][]{{"entityComment.comment", ESortOrder.asc.name()}}, firstRecord, numRecords);
		//Map<EntityRelationship, EntityComment> search = new HashMap<EntityRelationship, EntityComment>();
		MultiValueMap search = new MultiValueMap();
		for(Object i: list) {
			Map map = (Map)i;
			EntityRelationship er = (EntityRelationship)map.get(Criteria.ROOT_ALIAS);
			loadProperties(er);
			EntityComment ec = (EntityComment)map.get("entityComment");
			search.put(er, ec);
		}
		return search;
	}
	public long countBySample(EntityRelationship filter) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		makeFilter(filter, restrictionBuilder);
		return super.getSize(new String[]{"entity as entity", "entity.listValues as listValue", "entityParent as entityParent", "entity.entityComments as entityComment", "entity.keyValues as keyValue"}, restrictionBuilder);
	}	
	public List<EntityRelationship> findBySample(EntityRelationship filter, int firstRecord, int numRecords) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		makeFilter(filter, restrictionBuilder);
		return super.getByRestriction(new String[]{"entity as entity", "entity.listValues as listValue", "entityParent as entityParent", "entity.entityComments as entityComment", "entity.keyValues as keyValue"}, restrictionBuilder, null, firstRecord, numRecords);
	}
	
	public void makeFilter(EntityRelationship filter, IRestrictionBuilder restrictionBuilder) {
		if(filter!=null&&restrictionBuilder!=null) {
			if(filter.getEntity()!=null) {
				Entity entity = filter.getEntity();
				if(entity.getEntityId()>0)
					restrictionBuilder.addConditionAnd("entity.entityId", ERestrictionOperator.EQ, entity.getEntityId());
				if(!StringUtils.isEmpty(entity.getCode()))
					restrictionBuilder.addConditionAnd("entity.code", ERestrictionOperator.LK, "%"+entity.getCode()+"%");
				if(!StringUtils.isEmpty(entity.getDescription()))
					restrictionBuilder.addConditionAnd("entity.description", ERestrictionOperator.LK, "%"+entity.getDescription()+"%");
				if(!StringUtils.isEmpty(entity.getName()))
					restrictionBuilder.addConditionAnd("entity.name", ERestrictionOperator.LK, "%"+entity.getName()+"%");
				if(entity.getEntityType()!=null) {
					EntityType entityType = entity.getEntityType();
					if(entityType.getEntityTypeId()>0)
						restrictionBuilder.addConditionAnd("entity.entityType.entityTypeId", ERestrictionOperator.EQ, entityType.getEntityTypeId());
				}
				if(entity.getEntityComments()!=null&&entity.getEntityComments().size()>0) {
					EntityComment entityComment = (EntityComment)entity.getEntityComments().toArray()[0];
					if(!StringUtils.isEmpty(entityComment.getComment()))
						restrictionBuilder.addConditionAnd("entityComment.comment", ERestrictionOperator.LK, "%"+entityComment.getComment()+"%");
					if(entityComment.getEntityCommentId()>0)
						restrictionBuilder.addConditionAnd("entityComment.entityCommentId", ERestrictionOperator.EQ, entityComment.getEntityCommentId());
					if(entityComment.getCommentType()!=null) {
						CommentType commentType = entityComment.getCommentType();
						if(commentType.getCommentTypeId()>0)
							restrictionBuilder.addConditionAnd("entityComment.commentType.commentTypeId", ERestrictionOperator.EQ, entityComment.getCommentType().getCommentTypeId());
					}
				}
				if(entity.getKeyValues()!=null&&entity.getKeyValues().size()>0) {
					for(KeyValue keyValue: entity.getKeyValues()) {
						if(keyTypeProvider.isLIST(keyValue.getKeyDefinition().getKeyType())) {
							if(!StringUtils.isEmpty(keyValue.getVarcharValue()))
								restrictionBuilder.addConditionAnd("listValue.listValue", ERestrictionOperator.LK, "%"+keyValue.getVarcharValue()+"%");								
						} else {
							if(keyValue.getDateValue()!=null)
								restrictionBuilder.addConditionAnd("keyValue.dateValue", ERestrictionOperator.EQ, keyValue.getDateValue());
							if(keyValue.getEnumValue()!=null && keyValue.getEnumValue().getEnumValueId()>0)
								restrictionBuilder.addConditionAnd("keyValue.enumValue.enumValueId", ERestrictionOperator.EQ, keyValue.getEnumValue().getEnumValueId());
							if(keyValue.getNumericValue()!=null)
								restrictionBuilder.addConditionAnd("keyValue.numericValue", ERestrictionOperator.EQ, keyValue.getNumericValue());
							if(!StringUtils.isEmpty(keyValue.getVarcharValue()))
								restrictionBuilder.addConditionAnd("keyValue.varcharValue", ERestrictionOperator.LK, "%"+keyValue.getVarcharValue()+"%");
						}
					}
				}
			}
		}
	}
	public EntityTypeProvider getEntityTypeProvider() {
		return entityTypeProvider;
	}
	public void setEntityTypeProvider(EntityTypeProvider entityTypeProvider) {
		this.entityTypeProvider = entityTypeProvider;
	}
	public EntityRelationshipProvider(EntityTypeProvider entityTypeProvider, KeyTypeProvider keyTypeProvider) {
		this.entityTypeProvider = entityTypeProvider;
		this.keyTypeProvider = keyTypeProvider;
	}

	/***
	 * delete all entityRelationship descendants entities including
	 * entityRelationship entity
	 * @param entityRelationship 
	 * its hierarchical path is used to delete records, read only parameter
	 * @return 
	 * length of deleted entities
	 */
	public long deleteDescendants(EntityRelationship entityRelationship) {
		String sql = "delete from EntityRelationship er where er.hierarchicalPath like :hierarchicalPath||'%'";
		return super.executeUpdate(sql, new String[]{"hierarchicalPath"}, new Object[]{entityRelationship.getHierarchicalPath()});
	}
	
	/**
	 * lock elements up version
	 * @param entityRelationship
	 * its hierarchical path is used to update records, read only parameter
	 * @return
	 * length of updated entities
	 */
	public long updateVersionDescendants(EntityRelationship entityRelationship) {
		String sql = "update EntityRelationship set version = version + 1 where hierarchicalPath like :hierarchicalPath||'%'";
		return super.executeUpdate(sql, new String[]{"hierarchicalPath"}, new Object[]{entityRelationship.getHierarchicalPath()});
	}
	
	/***
	 * change hierarchical path from currentParameterRelationship descendants to 
	 * newParentRelationship hierarchical path
	 * @param currentParentRelationship
	 * its descendant entities will be changed, read only parameter
	 * @param newParentRelationship
	 * future parent entity, read only parameter
	 * @return 
	 * length of changed entities
	 */
	public long updateHierarchicalPath(EntityRelationship currentParentRelationship, EntityRelationship newParentRelationship) {
		int indexOf = currentParentRelationship.getHierarchicalPath().indexOf("/"+String.valueOf(currentParentRelationship.getEntity().getEntityId())+"/")+2;	
		String sql = "update EntityRelationship set hierarchicalPath = :newHierarchicalPath||substring(hierarchicalPath, :startPath), version = version + 1 ";
		sql = sql + " where hierarchicalPath like :hierarchicalPath||'%' and entityRelationshipId != :entityRelationshipId";
		return super.executeUpdate(sql, new String[]{"newHierarchicalPath", "startPath", "hierarchicalPath", "entityRelationshipId"}, new Object[]{newParentRelationship.getHierarchicalPath(), indexOf, currentParentRelationship.getHierarchicalPath(), currentParentRelationship.getEntityRelationshipId()});
	}	

	/***
	 * increment position on entityRelationshipParent children
	 * @param entityRelationshipParent
	 * its children will be incremented, read only parameter
	 * @param startPosition
	 * entities grater than or equal startPosition, with -1 is ignored
	 * @param endPosition
	 * entities less than or equal endPosition , with -1 is ignored
	 * @return
	 * length of updated entities
	 */
	public long updatePositionUp(EntityRelationship entityRelationshipParent, int startPosition, int endPosition) {
		List<String> names = new ArrayList<String>();
		List<Object> values = new ArrayList<Object>();
		String sql = "update EntityRelationship set position = position + 1, version = version + 1 ";
		sql = sql + " where entityParent.entityId = :entityId and hierarchicalPath like :hierarchicalPath||'%' ";
		names.add("entityId");
		values.add(entityRelationshipParent.getEntity().getEntityId());
		names.add("hierarchicalPath");
		values.add(entityRelationshipParent.getHierarchicalPath());
		if(startPosition>-1) {
			sql = sql + " and position >= :startPosition";
			names.add("startPosition");
			values.add(startPosition);
		}
		if(endPosition>-1) {
			sql = sql + " and position <= :endPosition";
			names.add("endPosition");
			values.add(endPosition);
		}
		return super.executeUpdate(sql, names.toArray(), values.toArray());				
	}	
	
	/***
	 * decrement position on entityRelationshipParent children
	 * @param entityRelationshipParent
	 * its children will be decremented, read only parameter
	 * @param startPosition
	 * entities grater than or equal startPosition, with -1 is ignored
	 * @param endPosition
	 * entities less than or equal endPosition , with -1 is ignored
	 * @return
	 * length of updated entities
	 */
	public long updatePositionDown(EntityRelationship entityRelationshipParent, int startPosition, int endPosition) {
		List<String> names = new ArrayList<String>();
		List<Object> values = new ArrayList<Object>();		
		String sql = "update EntityRelationship set position = position - 1, version = version + 1 ";
		sql = sql + " where entityParent.entityId = :entityId and hierarchicalPath like :hierarchicalPath||'%'";
		names.add("entityId");
		values.add(entityRelationshipParent.getEntity().getEntityId());
		names.add("hierarchicalPath");
		values.add(entityRelationshipParent.getHierarchicalPath());
		if(startPosition>-1) {
			sql = sql + " and position >= :startPosition";
			names.add("startPosition");
			values.add(startPosition);
		}
		if(endPosition>-1) {
			sql = sql + " and position <= :endPosition";
			names.add("endPosition");
			values.add(endPosition);
		}
		return super.executeUpdate(sql, names.toArray(), values.toArray());				
	}	
	
	/***
	 * it obtains entities children of parent entity
	 * @param parent
	 * its children will be returned, read only parameter
	 * @param orderBy
	 * to order the list
	 * @return
	 * children list of parent entity
	 */
	public List<EntityRelationship> getByParent(EntityRelationship parent, String[][] orderBy, List<Integer> entityTypeIds) {
		return this.getByIdAndPath(parent.getEntity().getEntityId(), parent.getHierarchicalPath(), orderBy, entityTypeIds);
	}	

	public List<EntityRelationship> getDescendants(String hierarchicalPath, String[][] orderBy, List<Integer> entityTypeIds) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		restrictionBuilder.addConditionAnd("entity.entityType.entityTypeId", ERestrictionOperator.IN, entityTypeIds.toArray());
		restrictionBuilder.addConditionAnd("hierarchicalPath", ERestrictionOperator.LK, hierarchicalPath+"%");
		return super.getByRestriction(new String[]{"entity as entity", "entityParent as entityParent"}, restrictionBuilder, orderBy, 0, -1);		
	}
	
	public List<EntityRelationship> getByIdAndPath(long entityParentId, String hierarchicalPath, String[][] orderBy, List<Integer> entityTypeIds) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		restrictionBuilder.addConditionAnd("entity.entityType.entityTypeId", ERestrictionOperator.IN, entityTypeIds.toArray());
		restrictionBuilder.addConditionAnd("entityParent.entityId", ERestrictionOperator.EQ, entityParentId);
		restrictionBuilder.addConditionAnd("hierarchicalPath", ERestrictionOperator.LK, hierarchicalPath+"%");
		return super.getByRestriction(new String[]{"entity as entity", "entityParent as entityParent"}, restrictionBuilder, orderBy, 0, -1);		
	}
	
	public List<EntityRelationship> getByEntityIds(long entityId, long entityParentId) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		restrictionBuilder.addConditionAnd("entityParent.entityId", ERestrictionOperator.EQ, entityParentId);
		restrictionBuilder.addConditionAnd("entity.entityId", ERestrictionOperator.EQ, entityId);
		return super.getByRestriction(new String[]{"entity as entity", "entityParent as entityParent"}, restrictionBuilder, null, 0, -1);
	}
	
	/***
	 * check if exits entities children of parent entity
	 * @param parent
	 * children to select for, read only parameter
	 * @return
	 * true when exits
	 */
	public boolean existsWithParent(EntityRelationship parent, List<Integer> entityTypeIds) {		
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		restrictionBuilder.addConditionAnd("entity.entityType.entityTypeId", ERestrictionOperator.IN, entityTypeIds.toArray());
		restrictionBuilder.addConditionAnd("entityParent.entityId", ERestrictionOperator.EQ, parent.getEntity().getEntityId());
		restrictionBuilder.addConditionAnd("hierarchicalPath", ERestrictionOperator.LK, parent.getHierarchicalPath()+"%");
		return super.existsWithRestriction(new String[]{"entity as entity", "entityParent as entityParent"}, restrictionBuilder);
	}	
	
	/**
	 * return a entity relationship with entity and entityParent properties load
	 * @param entityRelationshipId
	 * id to select
	 * @return
	 * entity relationship
	 */
	public EntityRelationship getByIdWithProperties(long entityRelationshipId) {
		IRestrictionBuilder restrictionBuilder = super.getRestrictionBuilder();
		restrictionBuilder.addConditionAnd("entityRelationshipId", ERestrictionOperator.EQ, entityRelationshipId);
		List<EntityRelationship> found = super.getByRestriction(new String[]{"entity as entity", "entityParent as entityParent"}, restrictionBuilder, null, 0, 1);
		if(found.size()==0)
			return null;
		else
			return found.get(0);
	}
	
	
	protected void loadProperties(EntityRelationship one) {
		one.getEntity().setEntityType(entityTypeProvider.getById(one.getEntity().getEntityType().getEntityTypeId()));
		one.getEntityParent().setEntityType(entityTypeProvider.getById(one.getEntityParent().getEntityType().getEntityTypeId()));
		if(one.getLink()!=null) {
			one.getLink().getEntity().setEntityType(entityTypeProvider.getById(one.getLink().getEntity().getEntityType().getEntityTypeId()));
			one.getLink().getEntityParent().setEntityType(entityTypeProvider.getById(one.getLink().getEntityParent().getEntityType().getEntityTypeId()));
		}
	}
}
